import numpy as np
import cv2
import matplotlib.font_manager as fm
import os
import matplotlib.pyplot as plt

import copy
from skimage.feature import graycomatrix, graycoprops

import detector

############################################################################################################3
# 此段代码实现对单张图片
# 1. 应用自适应直方图均衡化，并呈现结果
# 2. 应用多个Gabor卷积核，呈现卷积结果，并统计卷积结果的均值与方差
def example_1():
    single_img_path = "../fabric-defect/麻皮/T03825_00.bmp"
    img = detector.cv_read(single_img_path)
    detector.cv_show('image_raw', img)

    img_EquHisto = detector.AdaptiveEquHisto(img)
    detector.cv_show('img_EquHisto',img_EquHisto,block=False)

    params_set = detector.gen_params_set()
    filters = detector.build_filters(params_set)

    img_gabor = []
    img_gabor_title = []
    hists = []
    hists_title = []

    for kern,params in filters:
        img_gabor.append(kern)
        img_filted = cv2.filter2D(img_EquHisto, -1, kern)
        params_fstring = detector.gen_params_string(params)
        img_gabor.append(img_filted)
        img_gabor_title.append(params_fstring)
        img_gabor_title.append(params_fstring)
        hists.append(np.bincount(img_filted.ravel(), minlength=256))
        means, dev = cv2.meanStdDev(img_filted)
        hists_title.append(params_fstring + '\nmeans:{} dev:{}'.format(means, dev))

    detector.display_imgs(img_gabor,img_gabor_title,num_cols=4,main_title=single_img_path)
    detector.display_hists(hists,hists_title,num_cols=2, main_title=single_img_path)

    # 把 plt.show() 放到最后，可以同时呈现多个单独的图
    plt.show()
#################################################################################################


############################################################################################################3
# 此段代码实现对单张图片
# 1. 应用自适应直方图均衡化
# 2. 取ROI
# 3. 应用多个Gabor卷积核，呈现卷积结果，并统计卷积结果的均值与方差
def example_2():
    single_img_path = "../fabric-defect/麻皮/T03825_00.bmp"
    img = detector.cv_read(single_img_path)
    # detector.cv_show('image_raw', img)

    img_EquHisto = detector.AdaptiveEquHisto(img)
    # detector.cv_show('img_EquHisto',img_EquHisto)

    top_left = [0,0]
    buttom_right = [200,200]
    roi = detector.get_roi(img_EquHisto,top_left, buttom_right)
    detector.cv_show('roi',roi,block=False)

    params_set = detector.gen_params_set_theta_range(-np.pi/9, 0, np.pi/180)
    filters = detector.build_filters(params_set)

    img_gabor = []
    img_gabor_title = []
    hists = []
    hists_title = []

    for kern,params in filters:
        img_filted = cv2.filter2D(roi, -1, kern)
        params_fstring = detector.gen_params_string(params)
        img_gabor.append(img_filted)
        img_gabor_title.append(params_fstring)
        hists.append(np.bincount(img_filted.ravel(), minlength=256))
        means, dev = cv2.meanStdDev(img_filted)
        hists_title.append(params_fstring + '\nmeans:{} dev:{}'.format(means, dev))

    len_img_gabor = len(img_gabor)
    print(len_img_gabor)
    detector.display_imgs(img_gabor[:len_img_gabor//2],img_gabor_title[:len_img_gabor//2],num_cols=4,main_title=single_img_path)
    detector.display_imgs(img_gabor[len_img_gabor//2 +1:],img_gabor_title[len_img_gabor//2 +1:],num_cols=4,main_title=single_img_path)
    detector.display_hists(hists[:len_img_gabor//2],hists_title[:len_img_gabor//2],num_cols=2, main_title=single_img_path)
    detector.display_hists(hists[len_img_gabor//2+1:],hists_title[len_img_gabor//2+1:],num_cols=2, main_title=single_img_path)

    # 把 plt.show() 放到最后，可以同时呈现多个单独的图
    plt.show()
#################################################################################################

############################################################################################################3
# 此段代码实现对单张图片
# 1. 应用自适应直方图均衡化
# 2. 取ROI
# 3. 应用单个Gabor卷积核，呈现卷积结果，
# 4. 对卷积结果做线条检测，画出线条，
# 5. 计算线条斜率，剔除离群值，取平均斜率
def example_3():
    single_img_path = "../fabric-defect/麻皮/T03825_00.bmp"
    img = detector.cv_read(single_img_path)
    img_EquHisto = detector.AdaptiveEquHisto(img)
    top_left = [0,0]
    buttom_right = [120,200]
    roi_equhisto = detector.get_roi(img_EquHisto,top_left, buttom_right)

    ksize = 100 
    params = {'ksize':(ksize, ksize), 
                    'sigma':5, 
                    'theta':0,                                # theta代表条纹旋转角度
                    'lambd':8,                                   # lambd为波长 波长越大 条纹越大
                    'gamma':1,                                  # gamma越大核函数图像越小，条纹数不变，sigma越大 条纹和图像都越大
                    'psi':0,                                   # psi 是相位偏移 psi这里接近0度以白条纹为中心，180度时以黑条纹为中心
                    'ktype':cv2.CV_32F}

    kern = cv2.getGaborKernel(**params)
    img_gabor = cv2.filter2D(roi_equhisto, -1, kern)

    detector.cv_show("roi_equhisto", roi_equhisto, block=False)
    detector.cv_show("img_gabor",img_gabor,block=False)

    # 创建一个LSD对象
    lsd = cv2.createLineSegmentDetector(0)
    # 执行检测结果
    dlines = lsd.detect(img_gabor)

    # 绘制检测结果
    img_gabor_line = detector.draw_lines(img_gabor, dlines, (0,255,0), 1)

    # 计算线条的斜率
    slopes = []
    for dline in dlines[0]:
        slopes.append(detector.get_slope(dline))

    slopes = np.array(slopes)
    print(slopes)
    print("slope_mean:{}".format(slopes.mean()))

    # 取平均斜率
    new_slopes = detector.remove_outliers_sigma(slopes,1)
    print(new_slopes)
    print("new_slopes_mean:{}".format(new_slopes.mean()))

    detector.cv_show("img_gabor_line",img_gabor_line,block=False)
    detector.cv_show("kern",kern,block=True)


    # 把 plt.show() 放到最后，可以同时呈现多个单独的图
    plt.show()
#################################################################################################
    
############################################################################################################3
# 此段代码实现对单张图片
# 1. 应用自适应直方图均衡化
# 2. 取左上角和右上角ROI
# 3. 应用单个Gabor卷积核，呈现卷积结果
# 4. 对卷积结果做线条检测，取平均斜率
# 5. 根据左右上角纹理的平均斜率取原本方形块的4个点
# 6. 对取到点的连线所包围的区域做透视变换，使纹理横平竖直，并展示结果
def example_4():
    single_img_path = "../fabric-defect/麻皮/T03825_00.bmp"
    img = detector.cv_read(single_img_path)
    img_EquHisto = detector.AdaptiveEquHisto(img)

    # 取左上角的ROI
    top_left = [0,0]
    buttom_right = [120,200]
    roi_top_left = detector.get_roi(img_EquHisto,top_left, buttom_right)

    # 取右上角的ROI
    [height, width] = img_EquHisto.shape

    top_left = [width-121, 0]
    buttom_right = [width-1,200]
    roi_top_right = detector.get_roi(img_EquHisto,top_left, buttom_right)

    ksize = 100 
    params = {'ksize':(ksize, ksize), 
                    'sigma':5, 
                    'theta':0,                                # theta代表条纹旋转角度
                    'lambd':8,                                   # lambd为波长 波长越大 条纹越大
                    'gamma':1,                                  # gamma越大核函数图像越小，条纹数不变，sigma越大 条纹和图像都越大
                    'psi':0,                                   # psi 是相位偏移 psi这里接近0度以白条纹为中心，180度时以黑条纹为中心
                    'ktype':cv2.CV_32F}

    kern = cv2.getGaborKernel(**params)
    roi_top_left_gabor = cv2.filter2D(roi_top_left, -1, kern)
    roi_top_right_gabor = cv2.filter2D(roi_top_right, -1, kern)

    slope_top_left = detector.calc_mean_slope(roi_top_left_gabor)
    slope_top_right = detector.calc_mean_slope(roi_top_right_gabor)

    print("slope_top_left:{}, slope_top_right:{}".format(slope_top_left,slope_top_right))

    '''
    已知斜率k与一点(x0, y0)，又知另一点的一个坐标y, 求直线方程上另一点的x。

    (y - y0) = k*(x - x0)
    y - y0 = k*(x - x0)
    (y - y0)/k = x - x0
    x = (y - y0)/k + x0
    '''
    # 透视变换，需要取原图的4个顶点，变换到新的4个位置上
    point_top_left = [0,0]
    point_top_right = [width-1, 0]
    point_buttom_left = [0, height]
    point_buttom_right = [0, height]

    point_buttom_left[0] = (point_buttom_left[1] - point_top_left[1]) / slope_top_left + point_top_left[0]
    point_buttom_right[0] = (point_buttom_right[1] - point_top_right[1]) / slope_top_right + point_top_right[0]

    points = [point_top_left, point_top_right, point_buttom_left, point_buttom_right]
    img_draw_point = detector.draw_points(img_EquHisto,points,(255,0,0),3,8)

    dst_width = point_buttom_right[0]-point_buttom_left[0]
    dst_width = np.round(dst_width).astype(int)
    dst = [[0,0],[dst_width,0],[0,height],[dst_width,height]]
    img_Standardize = detector.PerspectiveTransform(img_EquHisto,points,dst,(dst_width,height))

    detector.cv_show("img_draw_point", img_draw_point, block=False)
    detector.cv_show("roi_top_left", roi_top_left, block=False)
    detector.cv_show("roi_top_left_gabor",roi_top_left_gabor,block=False)
    detector.cv_show("roi_top_right", roi_top_right, block=False)
    detector.cv_show("roi_top_right_gabor",roi_top_right_gabor,block=False)
    detector.cv_show("img_Standardize",img_Standardize,block=False)

    detector.cv_show("kern",kern,block=True)


    # 把 plt.show() 放到最后，可以同时呈现多个单独的图
    plt.show()
#################################################################################################
    
############################################################################################################
# 此段代码实现对三个文件夹中的所有图片
# 1. 应用自适应直方图均衡化
# 2. 取左上角和右上角ROI
# 3. 应用单个Gabor卷积核
# 4. 对卷积结果做线条检测，取平均斜率
# 5. 根据左右上角纹理的平均斜率取原本方形块的4个点
# 6. 对取到点的连线所包围的区域做透视变换，使纹理横平竖直
# 7. 保存所有处理后的图片
def example_5():
    dir_names = ["../fabric-defect/受损+紧经", "../fabric-defect/油污+缺纬", "../fabric-defect/麻皮"]
    for dir_name in dir_names:
        for imgname in os.listdir(dir_name):
            full_path = os.path.join(dir_name,imgname)
            img_raw = detector.cv_read(full_path)
            img_EquHisto = detector.AdaptiveEquHisto(img_raw)

            # 取左上角的ROI
            top_left = [0,0]
            buttom_right = [120,200]
            roi_top_left = detector.get_roi(img_EquHisto,top_left, buttom_right)

            # 取右上角的ROI
            [height, width] = img_EquHisto.shape

            top_left = [width-121, 0]
            buttom_right = [width-1,200]
            roi_top_right = detector.get_roi(img_EquHisto,top_left, buttom_right)

            ksize = 100 
            params = {'ksize':(ksize, ksize), 
                    'sigma':5, 
                    'theta':0,                                # theta代表条纹旋转角度
                    'lambd':8,                                   # lambd为波长 波长越大 条纹越大
                    'gamma':1,                                  # gamma越大核函数图像越小，条纹数不变，sigma越大 条纹和图像都越大
                    'psi':0,                                   # psi 是相位偏移 psi这里接近0度以白条纹为中心，180度时以黑条纹为中心
                    'ktype':cv2.CV_32F}

            kern = cv2.getGaborKernel(**params)
            roi_top_left_gabor = cv2.filter2D(roi_top_left, -1, kern)
            roi_top_right_gabor = cv2.filter2D(roi_top_right, -1, kern)

            slope_top_left = detector.calc_mean_slope(roi_top_left_gabor)
            slope_top_right = detector.calc_mean_slope(roi_top_right_gabor)

            '''
            已知斜率k与一点(x0, y0)，又知另一点的一个坐标y, 求直线方程上另一点的x。

            (y - y0) = k*(x - x0)
            y - y0 = k*(x - x0)
            (y - y0)/k = x - x0
            x = (y - y0)/k + x0
            '''
            # 透视变换，需要取原图的4个顶点，变换到新的4个位置上
            point_top_left = [0,0]
            point_top_right = [width-1, 0]
            point_buttom_left = [0, height]
            point_buttom_right = [0, height]

            point_buttom_left[0] = (point_buttom_left[1] - point_top_left[1]) / slope_top_left + point_top_left[0]
            point_buttom_right[0] = (point_buttom_right[1] - point_top_right[1]) / slope_top_right + point_top_right[0]

            points = [point_top_left, point_top_right, point_buttom_left, point_buttom_right]
            img_draw_point = detector.draw_points(img_EquHisto,points,(255,0,0),3,8)

            dst_width = point_buttom_right[0]-point_buttom_left[0]
            dst_width = np.round(dst_width).astype(int)
            dst = [[0,0],[dst_width,0],[0,height],[dst_width,height]]
            img_Standardize = detector.PerspectiveTransform(img_EquHisto,points,dst,(dst_width,height))

            new_full_path = detector.gen_path(full_path, "_Standardize","_Standardize")
            detector.save_img(new_full_path, img_Standardize)
############################################################################################################
            
############################################################################################################
# 此段代码实现对单张图片
# 1. 应用自适应直方图均衡化
# 2. 取左上角和右上角ROI
# 3. 应用单个Gabor卷积核，呈现卷积结果
# 4. 对卷积结果做线条检测，取平均斜率
# 5. 根据左右上角纹理的平均斜率取原本方形块的4个点
# 6. 对取到点的连线所包围的区域做透视变换，使纹理横平竖直，并展示结果
# 7. 构建Gabor滤波器,在多个方向上做卷积，并展示结果
# 8. 对多个方向做过卷积后的提取的纹理，计算灰度共生矩阵，并展示结果
def example_6():
    single_img_path = "../fabric-defect/油污+缺纬/T03903_00.bmp"
    img = detector.cv_read(single_img_path)
    img_EquHisto = detector.AdaptiveEquHisto(img)

    # 取左上角的ROI
    top_left = [0,0]
    buttom_right = [120,200]
    roi_top_left = detector.get_roi(img_EquHisto,top_left, buttom_right)

    # 取右上角的ROI
    [height, width] = img_EquHisto.shape

    top_left = [width-121, 0]
    buttom_right = [width-1,200]
    roi_top_right = detector.get_roi(img_EquHisto,top_left, buttom_right)

    ksize = 100 
    params = {'ksize':(ksize, ksize), 
                    'sigma':5, 
                    'theta':0,                                # theta代表条纹旋转角度
                    'lambd':8,                                   # lambd为波长 波长越大 条纹越大
                    'gamma':1,                                  # gamma越大核函数图像越小，条纹数不变，sigma越大 条纹和图像都越大
                    'psi':0,                                   # psi 是相位偏移 psi这里接近0度以白条纹为中心，180度时以黑条纹为中心
                    'ktype':cv2.CV_32F}

    kern = cv2.getGaborKernel(**params)
    roi_top_left_gabor = cv2.filter2D(roi_top_left, -1, kern)
    roi_top_right_gabor = cv2.filter2D(roi_top_right, -1, kern)

    slope_top_left = detector.calc_mean_slope(roi_top_left_gabor)
    slope_top_right = detector.calc_mean_slope(roi_top_right_gabor)

    print("slope_top_left:{}, slope_top_right:{}".format(slope_top_left,slope_top_right))

    '''
    已知斜率k与一点(x0, y0)，又知另一点的一个坐标y, 求直线方程上另一点的x。

    (y - y0) = k*(x - x0)
    y - y0 = k*(x - x0)
    (y - y0)/k = x - x0
    x = (y - y0)/k + x0
    '''
    # 透视变换，需要取原图的4个顶点，变换到新的4个位置上
    point_top_left = [0,0]
    point_top_right = [width-1, 0]
    point_buttom_left = [0, height]
    point_buttom_right = [0, height]

    point_buttom_left[0] = (point_buttom_left[1] - point_top_left[1]) / slope_top_left + point_top_left[0]
    point_buttom_right[0] = (point_buttom_right[1] - point_top_right[1]) / slope_top_right + point_top_right[0]

    points = [point_top_left, point_top_right, point_buttom_left, point_buttom_right]
    img_draw_point = detector.draw_points(img_EquHisto,points,(255,0,0),3,8)

    dst_width = point_buttom_right[0]-point_buttom_left[0]
    dst_width = np.round(dst_width).astype(int)
    dst = [[0,0],[dst_width,0],[0,height],[dst_width,height]]
    img_Standardize = detector.PerspectiveTransform(img_EquHisto,points,dst,(dst_width,height))
    detector.cv_show("img_Standardize", img_Standardize)

    # 构建Gabor滤波器
    params_set = []
    for theta in np.arange(0, np.pi, np.pi / 4):                               #gabor方向 0 45 90 135 角度尺度的不同会导致滤波后图像不同
        params={'ksize':(400, 400), 
                'sigma':40, 
                'theta':theta,                                # theta代表条纹旋转角度
                'lambd':100,                                   # lambd为波长 波长越大 条纹越大
                'gamma':6,                                  # gamma越大核函数图像越小，条纹数不变，sigma越大 条纹和图像都越大
                'psi':0,                                   # psi 是相位偏移 psi这里接近0度以白条纹为中心，180度时以黑条纹为中心
                'ktype':cv2.CV_32F}
        params_set.append(params)

    filters = detector.build_filters(params_set)

    img_gabor = []
    img_gabor_title = []

    for kern,params in filters:
        img_filted = cv2.filter2D(img_Standardize, -1, kern)
        params_fstring = detector.gen_params_string(params)
        img_gabor.append(img_filted)
        img_gabor_title.append(params_fstring)

    img_gabor_phi0 = img_gabor[0]
    img_gabor_phi = img_gabor[1]

    dist = [1,7,68]
    degree = [0,np.pi/2]
    detector.calc_glcm_coprops(img_gabor_phi0, 16, dist, degree, show=True,main_title="img_gabor_phi0")
    detector.calc_glcm_coprops(img_gabor_phi, 16, dist, degree, show=True,main_title="img_gabor_phi")

    # 把 plt.show() 放到最后，可以同时呈现多个单独的图
    plt.show()


############################################################################################################
# 此段代码实现对单张图片
# 1. 应用自适应直方图均衡化
# 2. 取左上角和右上角ROI
# 3. 应用单个Gabor卷积核，呈现卷积结果
# 4. 对卷积结果做线条检测，取平均斜率
# 5. 根据左右上角纹理的平均斜率取原本方形块的4个点
# 6. 对取到点的连线所包围的区域做透视变换，使纹理横平竖直，并展示结果
# 7. 在同一块材质正常的布料上取不同大小的纹理块
# 8. 分别计算不同距离，不同角度的灰度共生矩阵及统计量，并展示结果
def example_7():
    single_img_path = "../fabric-defect/麻皮/T03831_00.bmp"
    img = detector.cv_read(single_img_path)
    img_EquHisto = detector.AdaptiveEquHisto(img)

    # 取左上角的ROI
    top_left = [0,0]
    buttom_right = [120,200]
    roi_top_left = detector.get_roi(img_EquHisto,top_left, buttom_right)

    # 取右上角的ROI
    [height, width] = img_EquHisto.shape

    top_left = [width-121, 0]
    buttom_right = [width-1,200]
    roi_top_right = detector.get_roi(img_EquHisto,top_left, buttom_right)

    ksize = 100 
    params = {'ksize':(ksize, ksize), 
                    'sigma':5, 
                    'theta':0,                                # theta代表条纹旋转角度
                    'lambd':8,                                   # lambd为波长 波长越大 条纹越大
                    'gamma':1,                                  # gamma越大核函数图像越小，条纹数不变，sigma越大 条纹和图像都越大
                    'psi':0,                                   # psi 是相位偏移 psi这里接近0度以白条纹为中心，180度时以黑条纹为中心
                    'ktype':cv2.CV_32F}

    kern = cv2.getGaborKernel(**params)
    roi_top_left_gabor = cv2.filter2D(roi_top_left, -1, kern)
    roi_top_right_gabor = cv2.filter2D(roi_top_right, -1, kern)

    slope_top_left = detector.calc_mean_slope(roi_top_left_gabor)
    slope_top_right = detector.calc_mean_slope(roi_top_right_gabor)

    print("slope_top_left:{}, slope_top_right:{}".format(slope_top_left,slope_top_right))

    '''
    已知斜率k与一点(x0, y0)，又知另一点的一个坐标y, 求直线方程上另一点的x。

    (y - y0) = k*(x - x0)
    y - y0 = k*(x - x0)
    (y - y0)/k = x - x0
    x = (y - y0)/k + x0
    '''
    # 透视变换，需要取原图的4个顶点，变换到新的4个位置上
    point_top_left = [0,0]
    point_top_right = [width-1, 0]
    point_buttom_left = [0, height]
    point_buttom_right = [0, height]

    point_buttom_left[0] = (point_buttom_left[1] - point_top_left[1]) / slope_top_left + point_top_left[0]
    point_buttom_right[0] = (point_buttom_right[1] - point_top_right[1]) / slope_top_right + point_top_right[0]

    points = [point_top_left, point_top_right, point_buttom_left, point_buttom_right]
    img_draw_point = detector.draw_points(img_EquHisto,points,(255,0,0),3,8)

    dst_width = point_buttom_right[0]-point_buttom_left[0]
    dst_width = np.round(dst_width).astype(int)
    dst = [[0,0],[dst_width,0],[0,height],[dst_width,height]]
    img_Standardize = detector.PerspectiveTransform(img_EquHisto,points,dst,(dst_width,height))
    detector.cv_show("img_Standardize", img_Standardize,block=True)

    # 在同一块材质正常的布料上取不同大小的纹理块，观察灰度共生矩阵统计量的稳定性
    normal_roi1 = detector.get_roi(img_Standardize,[1234,134],[2014,1734])
    normal_roi2 = detector.get_roi(img_Standardize,[1234,134],[2013,548])
    normal_roi3 = detector.get_roi(img_Standardize,[1486,155],[1691,1120])

    dist = [1,8,70]
    degree = [0,np.pi/2]
    detector.calc_glcm_coprops(normal_roi1, 16, dist, degree, show=True,main_title="normal_roi1")
    detector.calc_glcm_coprops(normal_roi2, 16, dist, degree, show=True,main_title="normal_roi2")
    detector.calc_glcm_coprops(normal_roi3, 16, dist, degree, show=True,main_title="normal_roi3")

    # 把 plt.show() 放到最后，可以同时呈现多个单独的图
    plt.show()
################################################################################




################################################################################
    '''
    此代码实现对切片的所有正常样片：
    1. 网格切片为正常大小，如7*70,14*140，21*210，
    2. 对每个样片计算灰度共生矩阵的统计量
    3. 对每种参数组合（指glcm的参数[dist,degree]和统计量coprop的选择），计算所有结果的数列的标准差和均值，并计数离群值的数量。
    4. 挑选标准差最小的前10种参数组合,发现有部分参数的标准差为0
    '''
def example_8():
    # 构造了所有样片的数列
    dir_name = "../fabric-defect/crop_normal"
    slices = []
    for imgname in os.listdir(dir_name):
        full_path = os.path.join(dir_name,imgname)
        slice_raw = detector.cv_read(full_path)
        slices.extend(detector.grid_slice_width_height(slice_raw,140,420))

    dist = [1,7,70]
    degree = [0,np.pi/2]
    coprops = {'contrast':0,
            'dissimilarity':0,
            'homogeneity':0,
            'energy':0,
            'correlation':0,
            'ASM':0
    }

    # 这个数组保存了所有样片在所有灰度共生矩阵参数组合下的所有统计量
    # 形状为[len(slices)][len(dist)]
    # 元素为coprops字典，字典长度[len(coprops)]
    all_coprops_by_glcm = []
    for single_slice in slices:
        glcm, coprops_by_glcm = detector.calc_glcm_coprops(single_slice,16,dist,degree)
        all_coprops_by_glcm.append(coprops_by_glcm)
    # print(f"{len(all_coprops_by_glcm)}, \
    #         {len(all_coprops_by_glcm[0])}, \
    #         {len(all_coprops_by_glcm[0][0])}, \
    #         {len(all_coprops_by_glcm[0][0][0])}")

    '''
    目标数组[len(dist)][len(degree)]
        数组元素：coprops字典，字典长度[len(coprops)]
            字典的key: props
                value：这组参数选择下的 所有样片 的统计量的（均值，方差，离群值个数，[离群值的样片序号]）

    创建空数列，用于存放同参数的不同 slice 的glcm的统计量的统计值

    按dist遍历：
        按degree遍历：
            按coprop遍历:
                按 slice 序号遍历：
                    取 这个slice 的 这个（dist，degree）下 的 这个字典 中 的 这个coprop 的值
                    加入 数列
                对这个数列求(均值，方差，离群值个数，离群值样片序号）
                存入 这个（dist，degree） 的 字典 的 这个 prop 的 值 中
    '''
    mean = 0
    variance = 0
    num_outliers = 0
    indices = []
    statistics_single = (mean,variance,num_outliers,indices)

    coprops_same_dist_degree = {'contrast':0,
                                'dissimilarity':0,
                                'homogeneity':0,
                                'energy':0,
                                'correlation':0,
                                'ASM':0
    }

    for prop in coprops_same_dist_degree:
        coprops_same_dist_degree[prop] = copy.deepcopy(statistics_single)

    statistics_same_degree = []
    for i in range(len(degree)):
        statistics_same_degree.append(copy.deepcopy(coprops_same_dist_degree))

    statistics_all = []
    for i in range(len(dist)):
        statistics_all.append(copy.deepcopy(statistics_same_degree))

    # print(f"{len(statistics_all)}, \
    #         {len(statistics_all[0])}, \
    #         {len(statistics_all[0][0])}, \
    #         {len(statistics_all[0][0]["contrast"])}")

    data_array = []
    std_array = []
    std_max_array = []
    outliers_array = []
    for i in range(len(dist)):
        for j in range(len(degree)):
            for prop in coprops_same_dist_degree.keys():
                for k in range(len(slices)):
                    data_array.append(coprops_by_glcm[i][j][prop])
                    len_array = len(data_array)
                # 在这里开始计算各项数值
                data_array = np.array(data_array)
                data_array = detector.remove_outliers_sigma(data_array,factor=1)
                mean = data_array.mean()
                variance = data_array.std()
                num_outliers = len(slices) - len(data_array)
                indices = []
                statistics_single = (mean,variance,num_outliers,indices)
                statistics_all[i][j][prop] = copy.deepcopy(statistics_single)
                if variance == 0:
                    print(f"dist:{dist[i]:2d}, degree:{degree[j]:1.2f}, prop:{prop:}, mean:{mean}")
                std_array.append(copy.deepcopy(variance))
                outliers_array.append(copy.deepcopy(num_outliers))
                data_array = [] # 清除数列，以便下一轮统计

    plt.subplot(1,2,1)
    plt.title("std_array")
    plt.plot(std_array)
    plt.subplot(1,2,2)
    plt.title("outliers_array")
    plt.plot(outliers_array)
    plt.show()


################################################################################
'''
此代码实现对单张图片：
1. 应用自适应直方图均衡化
2. 取左上角和右上角ROI
3. 应用单个Gabor卷积核，呈现卷积结果
4. 对卷积结果做线条检测，取平均斜率
5. 根据左右上角纹理的平均斜率取原本方形块的4个点
6. 对取到点的连线所包围的区域做透视变换，使纹理横平竖直，
7. 对图片的所有区域做网格化切块，切块大小[140,420]
8. 对所有切块分别计算几个特定的灰度共生矩阵统计量,并展示出来
'''
def example_9():
    single_img_path = "../fabric-defect/麻皮/T03831_00.bmp"
    img = detector.cv_read(single_img_path)
    img_EquHisto = detector.AdaptiveEquHisto(img)

    # 取左上角的ROI
    top_left = [0,0]
    buttom_right = [120,200]
    roi_top_left = detector.get_roi(img_EquHisto,top_left, buttom_right)

    # 取右上角的ROI
    [height, width] = img_EquHisto.shape

    top_left = [width-121, 0]
    buttom_right = [width-1,200]
    roi_top_right = detector.get_roi(img_EquHisto,top_left, buttom_right)

    ksize = 100 
    params = {'ksize':(ksize, ksize), 
                    'sigma':5, 
                    'theta':0,                                # theta代表条纹旋转角度
                    'lambd':8,                                   # lambd为波长 波长越大 条纹越大
                    'gamma':1,                                  # gamma越大核函数图像越小，条纹数不变，sigma越大 条纹和图像都越大
                    'psi':0,                                   # psi 是相位偏移 psi这里接近0度以白条纹为中心，180度时以黑条纹为中心
                    'ktype':cv2.CV_32F}

    kern = cv2.getGaborKernel(**params)
    roi_top_left_gabor = cv2.filter2D(roi_top_left, -1, kern)
    roi_top_right_gabor = cv2.filter2D(roi_top_right, -1, kern)

    slope_top_left = detector.calc_mean_slope(roi_top_left_gabor)
    slope_top_right = detector.calc_mean_slope(roi_top_right_gabor)

    '''
    已知斜率k与一点(x0, y0)，又知另一点的一个坐标y, 求直线方程上另一点的x。

    (y - y0) = k*(x - x0)
    y - y0 = k*(x - x0)
    (y - y0)/k = x - x0
    x = (y - y0)/k + x0
    '''
    # 透视变换，需要取原图的4个顶点，变换到新的4个位置上
    point_top_left = [0,0]
    point_top_right = [width-1, 0]
    point_buttom_left = [0, height]
    point_buttom_right = [0, height]

    point_buttom_left[0] = (point_buttom_left[1] - point_top_left[1]) / slope_top_left + point_top_left[0]
    point_buttom_right[0] = (point_buttom_right[1] - point_top_right[1]) / slope_top_right + point_top_right[0]

    points = [point_top_left, point_top_right, point_buttom_left, point_buttom_right]

    dst_width = point_buttom_right[0]-point_buttom_left[0]
    dst_width = np.round(dst_width).astype(int)
    dst = [[0,0],[dst_width,0],[0,height],[dst_width,height]]
    img_Standardize = detector.PerspectiveTransform(img_EquHisto,points,dst,(dst_width,height))
    slices, (slice_row, slice_col) = detector.grid_slice_width_height_grid(img_Standardize,140,420)
    # print(slice_row,slice_col)
    
    dist = 0
    degree = 0
    coprops = {'contrast':0,
            'dissimilarity':0,
            'homogeneity':0,
            'energy':0,
            'correlation':0,
            'ASM':0
    }
    prop = ''
    parameters_tuple = (dist, degree, prop)

    '''
    目标数据:all_slices_dicts, 保存了 所有slice 对于 特定glcm参数组 的 glcm统计量
    格式：长度为len(slices)的一维数组
        元素：字典
                key: 由参数组组成的字符串
                value： 由参数组计算的 glcm统计量
    '''
    parameters_tuple_list = []
    parameters_tuple_list.append((7, np.pi/2, 'energy')) 
    parameters_tuple_list.append((7, np.pi/2, 'correlation'))
    parameters_tuple_list.append((70, np.pi/2, 'energy'))
    parameters_tuple_list.append((70, np.pi/2, 'homogeneity'))

    def get_parameters_tuple_fstring(parameters_tuple):
        (dist, degree, prop) = parameters_tuple
        return f"dist:{dist:2d}, degree:{degree:1.2f}, prop:{prop}"

    single_slice_dict = {}
    for i in range(len(parameters_tuple_list)):
        single_slice_dict[get_parameters_tuple_fstring(parameters_tuple_list[i])] = 0

    all_slices_dicts = []
    for i in range(len(slices)):
        all_slices_dicts.append(copy.deepcopy(single_slice_dict))
        # 开始计算glcm
        for j in range(len(parameters_tuple_list)):
            (dist, degree, prop) = parameters_tuple_list[j]
            # 压缩图片灰度级
            table16 = np.array([(i//16) for i in range(256)]).astype("uint8")  # 16 levels
            gray16 = cv2.LUT(slices[i], table16)  # 灰度级压缩为 [0,15]
            glcm = graycomatrix(gray16, [dist], [degree], levels=16)
            feature = graycoprops(glcm, prop).round(8)
            all_slices_dicts[i][get_parameters_tuple_fstring((dist, degree, prop))] = feature

    # print(feature.shape)  #(1,1)

    for parameters_tuple in parameters_tuple_list:
        plt.figure(figsize=(slice_row*3, slice_col*3))
        plt.suptitle(single_img_path + ' glcm ' + get_parameters_tuple_fstring(parameters_tuple),
                     fontproperties = detector.get_font_yahei(13))
        for i in range(slice_row):
            for j in range(slice_col):
                plt.subplot(slice_row,slice_col,i*slice_col+j+1)
                # plt.title(f"{i},{j}")
                plt.title(f"{all_slices_dicts[i*slice_col+j][get_parameters_tuple_fstring(parameters_tuple)][0][0]:.4f}")
                # plt.text(1,50,f"{all_slices_dicts[i*slice_col+j][get_parameters_tuple_fstring(parameters_tuple)][0][0]:.4f}",
                #          color='red',size=14)
                plt.imshow(slices[i*slice_col+j], 'gray')
        plt.tight_layout()

    plt.show()